﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using Roborally.Spelleider;
using Roborally.CommonData.GlobaleTypes;
using Roborally.Scheidsrechter;
using Roborally.CommonData.Enums;

// Leden Nicole Schröder, Danny Mestriner, Rick Leerschen
// In deze klasse wordt het algoritme gemaakt. 
// Dit algoritme heeft 9 kaarten nodig en kiest uit die 9 kaarten, 5 kaarten die de speler zal gaan spelen.
// Bij de methodes in de klassen staat nog eens uitgelegd op welke manier ze de 5 kaarten kiezen.
namespace Roborally.Algoritme_Groep10
{
    public class Algoritme : ISpeler
    {
        int waardeTeller = 0;
        //ModelSpelerInfo info;
        List<Point> reparatielijst = new List<Point>();
        List<APICheck> eindPunten = new List<APICheck>();

        #region ISpeler Members
        public void KrijgtKaarten(List<IProgramKaart> Kaarten, SpelerGegevens Speler, CommonData.GlobaleTypes.IModel Bord)
        {
            haalBordUitElkaar(Bord);
            DiepteEerst(Bord, Kaarten, eindPunten, Speler);
        }

        public event LegKaartNeerEvent LegKaartNeer;
        public bool DoLegKaartNeer(Spelleider.SpelerLegtKaartenArgs data)
        {
            bool output = false;
            if (LegKaartNeer != null)
                output = LegKaartNeer(data);
            return output;
        }

        public event VoerZetUitEvent VoerZetUit;
        public SpelerGegevens DoVoerZetUit(SpelerGegevens Speler, IProgramKaart Kaart)
        {
            SpelerGegevens output = null;
            if (VoerZetUit != null)
                output = VoerZetUit(Speler, Kaart);
            return output;
        }
        #endregion
        //public OutputSpeler kiesKaart(InputSpeler input)
        //{
            
        //    haalBordUitElkaar(input.Model);
        //    OutputSpeler output = DiepteEerst(input.Model, input.GekregenKaart, eindPunten);
        //    return output;
        //}

       
        /// <summary>
        /// In deze methode wordt het Bord "uitelkaar gehaald" en worden een paar lijsten gevuld
        /// </summary>
        /// <param name="model">Het model dat we binnen krijgen </param>
        public void haalBordUitElkaar(CommonData.GlobaleTypes.IModel model)
        {
            for (int i = 0; i < model.Vakken.GetLength(0); i++)
            {
                for (int j = 0; j < model.Vakken.GetLength(1); j++)
                {

                    if (model.Vakken[i, j].KrijgType() == VakType.Checkpoint)
                    {
                        Point eindPunt = new Point();
                        APICheck check = new APICheck();
                        eindPunt.X = i;
                        eindPunt.Y = j;
                        check.Plek = eindPunt;
                        check.Nummer = model.Vakken[i, j].CheckpointNummer();
                        eindPunten.Add(check);

                    }
                    if (model.Vakken[i, j].KrijgType() == VakType.Reparatievak)
                    {
                        reparatielijst.Add(new Point(i, j));
                    }
                }
            }
        }
        
        /// <summary>
        /// Hier wordt via Depth-First gezocht na de beste 5 kaarten
        /// </summary>
        /// <param name="model">Het binnen gekregen model</param>
        /// <param name="gekregenKaarten">De binnen gekregen kaarten</param>
        /// <param name="eindPunt">De checkpoints</param>
        /// <returns></returns>
        private void DiepteEerst(CommonData.GlobaleTypes.IModel model, List<IProgramKaart> gekregenKaarten, List<APICheck> eindPunt,SpelerGegevens speler)
        {
            Point eind = new Point();
            OutputSpeler output = new OutputSpeler();
            Node node = new Node();
            Tree boom = new Tree(this);
            bool eersteKeer = true;
            Node besteWaarde = new Node();
            Stack<IProgramKaart> nogKiezen = new Stack<IProgramKaart>();
            node.NogDoenLijst = new List<IProgramKaart>();
            foreach (ProgramKaart k in gekregenKaarten)
            {
                node.NogDoenLijst.Add(k);
            }
            Stack<Node> S = new Stack<Node>();
            List<Node> K = new List<Node>();
            //info = new ModelSpelerInfo("Rick", 1, new Point(2, 2), RobotType.Blauw, Richting.Zuid, 0, 3, false, 0);
            for (int i = 0; i < eindPunt.Count; i++)
            {

                if (eindPunt[i].Nummer == (speler.LaatstBehaaldeVlag + 1))
                {
                    eind = eindPunt[i].Plek;
                }
            }
            node.Positie = speler.Positie;
            node.SpRichting = speler.Richting;
            node.Diepte = 0;
            node.RouteLijst = new List<IProgramKaart>();
            while (S.Count != 0|| eersteKeer)
            {
                eersteKeer = false;   
                while (node.Diepte < 5)
                {
                    if (S.Count != 0)
                    {
                        S.Pop();
                    }
                    S = boom.geefKinderen(model, node, S, speler);
                    if (S.Count > 0)
                    {
                        node = S.First();
                        //K.Add(S.First());
                    }
                }
              besteWaarde = waardeerbord(model, node, besteWaarde, eind,speler);
              S.Pop();
              if (S.Count != 0)
              {
                 
                  node = S.First();
              }
            }
            output.AntwoordKaarten = besteWaarde.RouteLijst;
            output.PowerDown = bepaalPowerDown(speler);
            for (int i = 0; i < output.AntwoordKaarten.Count; i++)
            {
                DoLegKaartNeer(new SpelerLegtKaartenArgs(speler.Speler,output.AntwoordKaarten[i],i) { 
                    GekozenKaart = output.AntwoordKaarten[i], 
                    KaartVakNummer = i, 
                    SpelerIdentificatie = speler.Speler });
            }
            
            
        }
        /// <summary>
        /// Hier wordt gekeken of de speler een powerdown wilt doen
        /// </summary>
        /// <param name="info">de info die nodig is om te gaan bepalen</param>
        /// <returns>true als er wel powerdown komt, false als dit niet het geval is</returns>
        private bool bepaalPowerDown(SpelerGegevens speler)
        {
            return false;  
        }
        /// <summary>
        /// Hier geven we een waarde aan het bord
        /// </summary>
        /// <param name="model">Het binnen gekregen model</param>
        /// <param name="huidgeToestand">De Node met de huidigetoestand </param>
        /// <param name="besteToestand">De node met de beste eind toestand</param>
        /// <param name="eindPunt">Het checkpoint</param>
        /// <returns></returns>
        private Node waardeerbord(IModel model, Node huidgeToestand, Node besteToestand,Point eindPunt,SpelerGegevens speler)
        {
            //int checknummer =  speler.LaatstBehaaldeVlag;
            if (waardeTeller != 0)
            {
                
                int huidigeX = huidgeToestand.Positie.X;
                int huidigeY = huidgeToestand.Positie.Y;
                
                int eindX = eindPunt.X;
                int eindY = eindPunt.Y;

                int verschilX = Math.Abs(eindX - huidigeX);
                int verschilY = Math.Abs(eindY - huidigeY);

                int waarde = verschilX + verschilY;
                waarde = bekijkMuren(waarde, huidigeX, huidigeY,model);
                huidgeToestand.Waarde = waarde;

                if (huidgeToestand.Waarde < besteToestand.Waarde)
                {
                    waardeTeller++;
                    return huidgeToestand;
                }
                else
                {
                    waardeTeller++;
                    return besteToestand;
                }
               
            }
            else
            {

                int huidigeX = huidgeToestand.Positie.X;
                int huidigeY = huidgeToestand.Positie.Y;

                int eindX = eindPunt.X;
                int eindY = eindPunt.Y;

                int verschilX = Math.Abs(eindX - huidigeX);
                int verschilY = Math.Abs(eindY - huidigeY);
                
                int waarde = verschilX + verschilY;
                waarde = bekijkMuren(waarde, huidigeX, huidigeY, model);
                huidgeToestand.Waarde = waarde;
                waardeTeller++;
                return huidgeToestand;
            }
            
        }
        /// <summary>
        /// Hier bekijkt het algo of er muren om het eindpunt heen staan
        /// </summary>
        /// <param name="waarde">De huidige waarde van het bord</param>
        /// <param name="huidigeX">De huidige X positie</param>
        /// <param name="huidigeY">De huidige y positie </param>
        /// <param name="model">Het binnen gekregen model</param>
        /// <returns></returns>
        private int bekijkMuren(int waarde, int huidigeX, int huidigeY, IModel model)
        {
            Size grootte = new Size();
            grootte.Height = model.Vakken.GetLength(1);
            grootte.Width = model.Vakken.GetLength(0);
            if (huidigeX > grootte.Width|| huidigeY > grootte.Height || huidigeY < 0|| huidigeX < 0)
            {
                return waarde;
            }
            else if (model.Vakken[huidigeX, huidigeY].KrijgMuur(Richting.Noord) == false)
            {
                    if (huidigeX == 0)
                    {
                       
                    }
                    else
                    {
                        if (model.Vakken[huidigeX - 1, huidigeY].KrijgMuur(Richting.Zuid) == false)
                        {
                        }
                        else
                        {
                            waarde += 1;
                        }
                    }

                }
                else
                {
                    waarde += 1;
                }



                if (model.Vakken[huidigeX, huidigeY].KrijgMuur(Richting.Oost) == false)
            {
                if (huidigeY == grootte.Width - 1)
                {

                }
                else
                {
                    if (model.Vakken[huidigeX, huidigeY + 1].KrijgMuur(Richting.West) == false)
                    {
                    }
                    else
                    {
                        waarde += 1;
                    }
                }

            }
            else
            {
                waarde += 1;
            }
                if (model.Vakken[huidigeX, huidigeY].KrijgMuur(Richting.Zuid) == false)
            {
                if (huidigeX == grootte.Height - 1)
                {

                }
                else
                {
                    if (model.Vakken[huidigeX + 1, huidigeY].KrijgMuur(Richting.Noord) == false)
                    {
                    }
                    else
                    {
                        waarde += 1;
                    }
                }
            }
            else
            {
                waarde += 1;
            }
                if (model.Vakken[huidigeX, huidigeY].KrijgMuur(Richting.West) == false)
            {
                if (huidigeY == 0)
                {

                }
                else
                {
                    if (model.Vakken[huidigeX, huidigeY - 1].KrijgMuur(Richting.Oost) == false)
                    {

                    }
                    else
                    {
                        waarde += 1;
                    }
                }
            }
            else
            {
                waarde += 1;
            }
            return waarde;
        }
    }
}


